-include common.mk

# os source code path, need `-include` instead of `include` for 'pseudo target'
-include $(BOARDPATH)/meta/arch/config.mk
-include $(BOARDPATH)/meta/portable/config.mk
-include $(BOARDPATH)/meta/system/config.mk
-include $(BOARDPATH)/meta/utils/config.mk
-include $(BOARDPATH)/meta/task/config.mk
-include $(BOARDPATH)/meta/driver/config.mk
-include $(BOARDPATH)/meta/itc/config.mk
-include $(BOARDPATH)/meta/memory/config.mk
-include $(BOARDPATH)/meta/shell/config.mk
-include $(BOARDPATH)/meta/kprocess/config.mk
-include $(BOARDPATH)/meta/testbench/config.mk

#
# Input arguments:
#	$(CC)			- C compiler
#	$(AS)			- ASM compiler
#	$(LD)			- Object linker
#	$(BOARDPATH)	- The board path
#	$(CFLAGS)		- C compiler flags
#	$(SFLAGS)		- ASM compiler flags
#	$(LFLAGS)		- Object linker flags
#	$(SRCDIRS)		- The full path of source files (.c .s .S)
#	$(INCDIRS)		- The full path of header files (.h)
#	$(IGNORES)		- The list of ignore files
# Optional input arguments:
#	$(TARGET)		- The final object file name, exclude path
#	$(V)			- Silent of not (pass by commandline)
# Optional Callback functions:
#	CB_COMPILE(target, depend)	- Called every time after compilation
#	CB_LINK(target, depend)		- Called after linker
#

# -------- parameters checkout

ifeq ($(CC),)
$(error CC should not be null)
endif
ifeq ($(LD),)
$(error LD should not be null)
endif
ifeq ($(AS),)
$(error AS should not be null)
endif
ifeq ($(BOARDPATH),)
$(error BOARDPATH should not be null)
endif

# -------- verbose contorl, `make V=1` to show the detail of compile

# the absolute path of matrix
ROOTPATH	:= $(abspath ./)

# note: must use the `=` instead of `:=` because of $</$@
SILENT		 = @
CMSG		 = @echo BUILD: $(subst $(ROOTPATH)/,,$<)
LMSG		 = @echo Generated: $(subst $(ROOTPATH)/,,$@)
ifeq ("$(origin V)", "command line")
	ifeq ($(V),1)
SILENT	 	 =
CMSG	 	 =
	endif
endif

# -------- makefile's arguments

TARGET		?= matrix

# -------- generate target file full path

# check whether the board folder contain matrix
ISCONTAIN_MX	:= $(and $(filter $(BOARDPATH)/%,$(ROOTPATH)),$(if $(filter $(BOARDPATH),$(ROOTPATH)),,yes))

# get the source files in `SRCDIRS`
SRCFILES	:= $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c))
SRCFILES	+= $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.cpp))
SRCFILES	+= $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.s))
SRCFILES	+= $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.S))

# remove ignore files
IGNORES		:= $(wildcard $(IGNORES))
SRCFILES	:= $(filter-out $(IGNORES), $(SRCFILES))

ifeq ($(ISCONTAIN_MX),yes)
# generate kernel objects (must be first)
OBJS		:= $(patsubst $(ROOTPATH)/%.c,$(BOARDPATH)/build/%.o,$(SRCFILES))
OBJS		:= $(patsubst $(ROOTPATH)/%.cpp,$(BOARDPATH)/build/%.o,$(OBJS))
OBJS		:= $(patsubst $(ROOTPATH)/%.s,$(BOARDPATH)/build/%.o,$(OBJS))
OBJS		:= $(patsubst $(ROOTPATH)/%.S,$(BOARDPATH)/build/%.o,$(OBJS))
# generate board objects
OBJS		:= $(patsubst $(BOARDPATH)/%.c,$(BOARDPATH)/build/board/%.o,$(OBJS))
OBJS		:= $(patsubst $(BOARDPATH)/%.cpp,$(BOARDPATH)/build/board/%.o,$(OBJS))
OBJS		:= $(patsubst $(BOARDPATH)/%.s,$(BOARDPATH)/build/board/%.o,$(OBJS))
OBJS		:= $(patsubst $(BOARDPATH)/%.S,$(BOARDPATH)/build/board/%.o,$(OBJS))
else
# generate board objects (must be first)
OBJS		:= $(patsubst $(BOARDPATH)/%.c,$(BOARDPATH)/build/board/%.o,$(SRCFILES))
OBJS		:= $(patsubst $(BOARDPATH)/%.cpp,$(BOARDPATH)/build/board/%.o,$(OBJS))
OBJS		:= $(patsubst $(BOARDPATH)/%.s,$(BOARDPATH)/build/board/%.o,$(OBJS))
OBJS		:= $(patsubst $(BOARDPATH)/%.S,$(BOARDPATH)/build/board/%.o,$(OBJS))
# generate kernel objects
OBJS		:= $(patsubst $(ROOTPATH)/%.c,$(BOARDPATH)/build/%.o,$(OBJS))
OBJS		:= $(patsubst $(ROOTPATH)/%.cpp,$(BOARDPATH)/build/%.o,$(OBJS))
OBJS		:= $(patsubst $(ROOTPATH)/%.s,$(BOARDPATH)/build/%.o,$(OBJS))
OBJS		:= $(patsubst $(ROOTPATH)/%.S,$(BOARDPATH)/build/%.o,$(OBJS))
endif

# -------- include path

I			:= $(subst $(ROOTPATH)/,,$(INCDIRS))
I			:= $(foreach dir,$(I),-I$(dir))

# -------- rules

# target file
$(BOARDPATH)/build/$(TARGET).elf : $(OBJS)
	$(SILENT) $(LD) $(LFLAGS) -o $@ $^
	$(LMSG)
	$(call CB_LINK, $@, $^)

# board object files
$(BOARDPATH)/build/board/%.o : $(BOARDPATH)/%.c
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(CC) $(CFLAGS) $(I) -o $@ $<
	$(call CB_COMPILE, $@, $<)
$(BOARDPATH)/build/board/%.o : $(BOARDPATH)/%.cpp
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(CC) $(CFLAGS) $(I) -o $@ $<
	$(call CB_COMPILE, $@, $<)
$(BOARDPATH)/build/board/%.o : $(BOARDPATH)/%.S
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(AS) $(SFLAGS) $(I) -o $@ $<
	$(call CB_COMPILE, $@, $<)
$(BOARDPATH)/build/board/%.o : $(BOARDPATH)/%.s
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(AS) $(SFLAGS) $(I) -o $@ $<
	$(call CB_COMPILE, $@, $<)

# kernel object files
$(BOARDPATH)/build/%.o : %.c
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(CC) $(CFLAGS) $(I) -o $@ $<
	$(call CB_COMPILE, $@, $<)
$(BOARDPATH)/build/%.o : %.cpp
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(CC) $(CFLAGS) $(I) -o $@ $<
	$(call CB_COMPILE, $@, $<)
$(BOARDPATH)/build/%.o : %.S
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(AS) $(SFLAGS) $(I) -o $@ $<
	$(call CB_COMPILE, $@, $<)
$(BOARDPATH)/build/%.o : %.s
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(AS) $(SFLAGS) $(I) -o $@ $<
	$(call CB_COMPILE, $@, $<)

# -------- pseudo target

.PHONY: clean

clean:
	$(SILENT)rm -rf $(BOARDPATH)/build/*
